import string
from numpy import random, array
import observer

# some aux functions
def findFactor(num, factor, prime):
    '''
    returns element i of GF(prime) such that i*factor = num
    '''
    for i in range(1, prime):
        if (i*factor)%prime == num:
            return i

class KeyDistributor:
    def __init__(self, key, prime):
        self.key = key
        self.prime = prime
        # parse file "ranks.txt" to get number of different type of observers
        ranksFile = open("ranks.txt", "r")
        ranksLines = [ line.rstrip() for line in ranksFile.readlines() ]
        lines = []
        for line in ranksLines:
            if len(line) == 0 or line[0] == '#':
                continue
            lines.append(line)
        self.ranks = {}
        for line in lines:
            linesplit = line.split(": ")
            self.ranks[linesplit[0]] = int(linesplit[1])
        # for each type of observer own number is needed: product of these numbers is equal to key
        self.secrets = {}.fromkeys(self.ranks.keys(),1)
        for i, rank in enumerate(self.secrets.keys()):
            if i != len(self.secrets.keys()) - 1:
                self.secrets[rank] = random.randint(0, self.prime, 1).item()
            else:
                # for last rank find secret S such that production of all secrets is equal to key
                factor = 1
                for s in self.secrets.values():
                    print s
                    factor *= s
                self.secrets[rank] = findFactor(self.key, factor, self.prime)
                    
        # dictionary containing how many keys have been already given to each type of observer
        self.keysGiven = {}.fromkeys(self.ranks.keys(), 0)
        # dict of observers to which keys were given
        self.observers = {}.fromkeys(self.ranks.keys())
        for rank in self.observers:
            self.observers[rank] = []
        # dictionary containing coefficients of polynomials
        self.poly = {}.fromkeys(self.ranks.keys())
        # generate coefficients of polymonials
        for rank in self.ranks:
            numOfCoeffs = self.ranks[rank]-1
            self.poly[rank] = random.randint(0, self.prime, numOfCoeffs)

    def giveKey(self, observer):
        '''
        observer is Observer class instance
        '''
        observerRank = observer.rank
        observerName = observer.name
        # check if observer has already been given the key
        if observerName in self.observers[observerRank]:
            print "This observer has already got the key"
            return
        else:
            self.observers[observerRank].append(observerName)
            self.keysGiven[observerRank] = self.keysGiven[observerRank] + 1
            x = self.keysGiven[observerRank]
            coeffs = self.poly[observerRank]
            y = (self.secrets[observerRank] + sum(coeffs * [(x**k)%self.prime for k in range(1,len(coeffs)+1)]))%self.prime
            return (x,y)
